'use strict';

const Service = require('egg').Service;

class RoleService extends Service {
    /*
    * 新增角色
    * */
    async create(name, isInit = true) {
        const { ctx } = this;
        const role = await ctx.model.Role.findOne({ name });
        if (role) {
            ctx.throw(402, '角色已存在', {
                code: 'role_not'
            });
        }
        // 权限验证
        if (isInit) {
            await ctx.powerValidate();
        }
        return await ctx.model.Role.create({ name });
    }

    /*
    * 修改角色
    * */
    async update(id, payload = {}) {
        const { ctx, app } = this;
        const role = await ctx.model.Role.findById(id);
        const roleName = await ctx.model.Role.findOne({ name: payload.name.trimAll() });
        if (!role) {
            ctx.throw(404, '角色不存在', {
                code: 'role_not'
            });
        }
        if (role._id === app.custom.admin._id) {
            ctx.throw(403, '不允许修改超级管理员角色', {
                code: 'root_role_stop'
            });
        }
        if (roleName) {
            ctx.throw(403, `角色名称${payload.name}已存在，无法使用此名称`, {
                code: 'role_error'
            });
        }
        // 权限验证
        await ctx.powerValidate();

        payload.updateAt = Date.now();
        return await ctx.model.Role.findByIdAndUpdate(id, payload);
    }

    /*
    * 删除角色
    * */
    async destroy(id) {
        const { ctx, app } = this;
        const role = await ctx.model.Role.findById(id);
        if (!role) {
            ctx.throw(404, '角色不存在', {
                code: 'role_not'
            });
        }
        // 权限验证
        await ctx.powerValidate();

        // 不允许删除超级管理员角色和普通用户角色
        if ([app.custom.role.admin.toString(), app.custom.role.ordinarylRole.toString()].includes(id)) {
            ctx.throw(403, '您不能删除超级管理员角色和普通用户角色', {
                code: 'power_not'
            });
        }
        return await ctx.model.Role.findByIdAndRemove(id);
    }

    /*
    * 获取角色
    * */
    async find({ id, name = '', page = 1, sort = 1, limit = 10 }, select = null) {
        const { ctx, app } = this;
        const routersPopulate = 'name id methods path createAt';
        if (id) {
            return await ctx.model.Role.findById(id).populate('routers', routersPopulate).select(select);
        } else {
            const res = await ctx.model.Role
                .find()
                .regex('name', new RegExp(name, 'i'))
                .populate('routers', routersPopulate)
                .sort({ createAt: sort })
                .skip((Number(page) - 1) * Number(limit))
                .limit(Number(limit))
                .select(select);
            const count = await ctx.model.Role
                .find()
                .regex('name', new RegExp(name, 'i'))
                .count();
            return {
                count,
                admin: app.custom.role.admin.toString(),
                page,
                list: res
            }
        }
    }

    /*
    * 为角色添加或者移除可访问的路由
    * */
    async roterCreateRouter(roleId, routerId, create = true) {
        const { ctx, app } = this;
        const role = await ctx.model.Role.findById(roleId);
        const router = await ctx.model.Router.findById(routerId);

        if (!role) {
            ctx.throw(404, '角色不存在', {
                code: 'role_not'
            });
        }
        if (!router) {
            ctx.throw(404, '路由不存在或是对外公开路由', {
                code: 'router_not'
            });
        }
        if (role._id.toString() === app.custom.role.admin.toString()) {
            ctx.throw(403, '不允许为超级管理员添加角色', {
                code: 'role_not_create'
            });
        }

        let payload = {
            updateAt: Date.now()
        }

        // 判断是增加还是移除路由
        if (create) {
            payload.$addToSet = {
                routers: routerId
            }
        } else {
            payload.$pull = {
                routers: routerId
            }
        }
        return await ctx.model.Role.findByIdAndUpdate(roleId, payload);
    }
}

module.exports = RoleService;
